﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using System.Windows;
using Infragistics.Documents.Excel;

namespace ibba.src.noriskbo.ViewModels
{
    public class ImportarOperacoesViewModel : Base.ViewModelImportacaoBase<ServiceOperacao.OperacaoManualImportacao>
    {
        private ServiceOperacao.IServiceOperacao _service;
        private LogAuditoria _msgLogAuditoria;

        public bool _erroNaValidacao;
        public bool _erroNaImportacao;

        public ImportarOperacoesViewModel()
        {
            base.TitleView = "Importação de Operações Manuais";

            if (!base.IsInDesignMode)
            {
                _service = ServiceFactory.Instance.ServiceOperacao;
                base.DadosPlanilha = new ObservableCollection<ServiceOperacao.OperacaoManualImportacao>();
            }
        }

        public void Clear()
        {
            DadosPlanilha.Clear();

            base.PlanilhaExcel = null;
            base.ExcelFileName = string.Empty;

            this.NotifyProperties();
        }

        #region [ Comandos de Botões ]

        protected override void CarregarDados(Worksheet pSheet)
        {
            int lin = 0;
            int col = 0;
            int colNull = 0;

            FileStream stream = null;

            try
            {
                base.StartBusy();

                DadosPlanilha.Clear();

                foreach (var r in pSheet.Rows)
                {
                    lin = r.Index;

                    if ((lin > 0) && (r.Cells[0] != null))
                    {
                        col = 0;
                        colNull = 0;

                        var item = new ServiceOperacao.OperacaoManualImportacao();

                        item.DataAbertura = DateTime.Now;
                        item.DataVencimento = DateTime.Now;

                        foreach (WorksheetCell cell in r.Cells)
                        {
                            SetValue(item, cell);

                            if (cell.Value == null)
                                colNull++;

                            ////Por padrão a leitura da coleção não efetua leitura de celulas nula
                            //if ((_col - cell.ColumnIndex) < 0)
                            //{
                            //    item.DescricaoErro = string.Format("Valor incorreto na celula {0}{1} da planilha.", Convert.ToChar(_col + 65), _lin);
                            //    item.StatusImportacao = Constantes.StatusImportLote.ERRO;
                            //}

                            col = cell.ColumnIndex;
                        }

                        if (colNull != r.Cells.Count())
                        {
                            if (item.CodigoContrato != null && item.CodigoContrato.Length > 20)
                                item.CodigoContrato = item.CodigoContrato.Substring(0, 20);

                            if (item.CodigoProduto != null && item.CodigoProduto.Length > 15)
                                item.CodigoProduto = item.CodigoProduto.Substring(0, 15);

                            if (item.CodigoModalidade != null && item.CodigoModalidade.Length > 15)
                                item.CodigoModalidade = item.CodigoModalidade.Substring(0, 15);

                            if (item.CodigoMoeda != null && item.CodigoMoeda.Length > 3)
                                item.CodigoMoeda = item.CodigoMoeda.Substring(0, 3);

                            DadosPlanilha.Add(item);
                        }
                    }

                }

            }
            catch (Exception ex)
            {
                if (lin > 0)
                    MessageBoxHelper.ShowErro(AppHelper.NomeSistema, string.Format("Ocorreu um erro na linha {0}, coluna {1}", lin + 1, col + 1), ex.Message.ToString());
                else
                    MessageBoxHelper.ShowErro(AppHelper.NomeSistema, "Não foi possível carregar o arquivo", ex.Message.ToString());
            }
            finally
            {
                if (stream != null)
                    stream.Close();

                base.NotifyProperties();
                base.EndBusy("Carregando...");
            }

        }
        
        public override void ComandoValidarDados()
        {
            InvokeValidarDadosDeImportacao();
        }
  
        public override void ComandoImportarDados()
        {
            int count = 0;
            System.Text.StringBuilder sb = new System.Text.StringBuilder();

            sb.AppendLine("ATENÇÃO: Você está solicitando:");

            count = this.InsertCount;
            if (count > 0)
                sb.AppendLine(String.Format("\nInclusão de Rascunho:\n\t > {0} {1}", count, count == 1 ? "operação" : "operações"));


            count = this.UpdateCount;
            if (count > 0)
                sb.AppendLine(String.Format("\nAlteração de Rascunho:\n\t > {0} {1}", count, count == 1 ? "operação" : "operações"));


            count = this.CopyCount;
            if (count > 0)
                sb.AppendLine(String.Format("\nCopia de Aprovado ou Automático:\n\t > {0} {1}", count, count == 1 ? "operação" : "operações"));


            _msgLogAuditoria = new LogAuditoria();
            _msgLogAuditoria.Mensagem = sb.ToString();

            MessageBoxHelper.ShowQuestion("Importação de Operações em Lote"
                        , sb.ToString()
                        , sl.componentes.CustomDialogEnums.enumCustomDialogIcons.Stop
                        , new sl.componentes.CustomDialog.DialogClosed((r) =>
                        {
                            if (r == MessageBoxResult.Yes)
                                SalvarDadosDeImportacao();
                            else
                                _msgLogAuditoria = null;
                        }));
        }

        protected override void ValidarRetornoDados(ServiceOperacao.OperacaoManualImportacao pEntidade)
        {
            ServiceOperacao.OperacaoManualImportacao dado;
            List<ServiceOperacao.OperacaoManualImportacao> dados;

            dados = DadosPlanilha.Where(a => a.CodigoContrato.Trim().ToUpper() == pEntidade.CodigoContrato.Trim().ToUpper()
                                          && a.CodigoProduto.Trim().ToUpper() == pEntidade.CodigoProduto.Trim().ToUpper()
                                          && a.CodigoModalidade.Trim().ToUpper() == pEntidade.CodigoModalidade.Trim().ToUpper()
                                          && a.IdCliente == pEntidade.IdCliente).ToList();


            for (int i = 0; i < dados.Count; i++)
            {
                if (i == 0)
                {
                    dado = dados[0];

                    //Atualiza dados do retorno
                    dado.IdOperacao = pEntidade.IdOperacao;
                    dado.IdProdutoRisco = pEntidade.IdProdutoRisco;
                    dado.NomeCliente = pEntidade.NomeCliente;
                    dado.IdCliente = pEntidade.IdCliente;
                    dado.IdVeiculo = pEntidade.IdVeiculo;
                    dado.Veiculo = pEntidade.Veiculo;
                    dado.CodigoStatus = pEntidade.CodigoStatus;
                    dado.IdAreaSubLimite = pEntidade.IdAreaSubLimite;
                    dado.AreaSubLimite = pEntidade.AreaSubLimite;
                    dado.CodigoMoeda = pEntidade.CodigoMoeda;
                    dado.IdEntidadeReferencia = pEntidade.IdEntidadeReferencia;
                    dado.NomeEntidadeReferencia = pEntidade.NomeEntidadeReferencia;

                    dado.DescricaoErro = string.Empty;

                    if (dado.IdOperacao == -1)
                    {
                        dado.DescricaoErro = "Ocorreu um erro com a importação deste registro!";
                    }
                    if (dado.IdOperacao > 0 
                        && (dado.CodigoStatus == Constantes.StatusFluxoLM.BAIXA_OPERACIONAL
                        || dado.CodigoStatus == Constantes.StatusFluxoLM.EM_EXCLUSAO_BAIXA_OPERACIONAL))
                    {
                        dado.DescricaoErro += "Existe uma BAIXA OPERACIONAL para este contrato\n";
                    }
                    if (dado.IdProdutoRisco == 0)
                    {
                        dado.DescricaoErro += "Codigo do Produto/Modalidade não encontrado!\n";
                    }
                    if (string.IsNullOrWhiteSpace(dado.NomeCliente))
                    {
                        dado.DescricaoErro += "Cliente não encontrado!\n";
                    }
                    if (string.IsNullOrWhiteSpace(dado.CodigoMoeda))
                    {
                        dado.DescricaoErro += "Codigo da Moeda não encontrada!\n";
                    }
                    //if (dado.IdOperacao == 0 && dado.IdVeiculo == 0)
                    //{
                    //    dado.DescricaoErro += "Para inclusões é necessário informar o Id do Veículo Legal!\n";
                    //}
                    if (dado.IdVeiculo == 0)
                    {
                        dado.DescricaoErro += "Veículo Legal não encontrado!\n";
                    }
                    if (dado.IdAreaSubLimite == 0)
                    {
                        dado.DescricaoErro += "Tipo de Sublimite não encontrado!\n";
                    }
                    if (dado.CodigoProduto == "CDS" && string.IsNullOrWhiteSpace(dado.NomeEntidadeReferencia))
                    {
                        dado.DescricaoErro += "Reference Entity não encontrada!\n";
                    }
                }
                else
                {
                    //Se retornou mais de uma registro na consulta marca como duplicado
                    dado = dados[i];
                    dado.DescricaoErro = "Registro duplicado na planilha!";
                }
                
                //Marca status da validação
                if (string.IsNullOrEmpty(dado.DescricaoErro) == false)
                    dado.StatusImportacao = Constantes.StatusImportLote.ERRO;
                else
                    if (dado.IdOperacao == 0)
                    {
                        dado.StatusImportacao = Constantes.StatusImportLote.INCLUSAO;
                    }
                    else
                    {
                        if (dado.CodigoStatus == Constantes.StatusFluxoLM.RASCUNHO
                            || dado.CodigoStatus == Constantes.StatusFluxoLM.EM_APROVACAO
                            || dado.CodigoStatus == Constantes.StatusFluxoLM.EM_BAIXA_OPERACIONAL
                            || string.IsNullOrEmpty(dado.CodigoStatus))
                            dado.StatusImportacao = base.IsImporting? Constantes.StatusImportLote.FINALIZADO : Constantes.StatusImportLote.ALTERACAO;
                        else
                            dado.StatusImportacao = base.IsImporting ? Constantes.StatusImportLote.FINALIZADO : Constantes.StatusImportLote.COPIAR;
                    }
            }
        }
                
        #endregion //Comandos Botoes

        #region [ Métodos adicionais ]

        /// <summary>
        /// Preenche e trata os valores da planilha excell
        /// </summary>
        /// <param name="pEntidade"></param>
        /// <param name="pCell"></param>
        /// 
        private void SetValue(ServiceOperacao.OperacaoManualImportacao pEntidade, WorksheetCell pCell)
        {
            try
            {
                var value = pCell.Value;
                DateTime dtAux;

                switch (pCell.ColumnIndex)
                {
                    case 0: pEntidade.CodigoContrato = Convert.ToString(value);
                        break;
                    case 1: pEntidade.CodigoProduto = Convert.ToString(value);
                        break;
                    case 2: pEntidade.CodigoModalidade = Convert.ToString(value);
                        break;
                    case 3: pEntidade.IdCliente = Convert.ToInt32(value);
                        break;
                    case 4:
                        if (DateTime.TryParse(value.ToString(), out dtAux))
                            pEntidade.DataAbertura = dtAux;
                        else
                            pEntidade.DataAbertura = DateTime.FromOADate(Convert.ToDouble(value));

                        break;
                    case 5:
                        if (DateTime.TryParse(value.ToString(), out dtAux))
                            pEntidade.DataVencimento = dtAux;
                        else
                            pEntidade.DataVencimento = DateTime.FromOADate(Convert.ToDouble(value));

                        break;
                    case 6: pEntidade.CodigoMoeda = value.ToString();
                        break;
                    case 7: pEntidade.ValorOperacao = Convert.ToDecimal(value);
                        break;
                    case 8: pEntidade.ValorContabil = Convert.ToDecimal(value);
                        break;
                    case 9: pEntidade.ValorComprometido = Convert.ToDecimal(value);
                        break;
                    case 10: pEntidade.BaixarNoVencimento = Convert.ToBoolean(value);
                        break;
                    case 11: pEntidade.SobrepoeAutomatica = Convert.ToBoolean(value);
                        break;
                    case 12: pEntidade.Veiculo = Convert.ToString(value);
                        break;
                    case 13: pEntidade.AreaSubLimite = Convert.ToString(value);
                        break;
                    case 14: pEntidade.ValorUpfrontFee = Convert.ToDecimal(value);
                        break;
                    case 15: pEntidade.ValorIndependentAmount = Convert.ToDecimal(value);
                        break;
                    case 16: pEntidade.IdEntidadeReferencia = Convert.ToInt32(value);
                        break;
                    default:
                        break;
                }

            }
            catch (Exception)
            {
                pEntidade.DescricaoErro = string.Format("Valor incorreto na celula {0}{1} da planilha.", Convert.ToChar(pCell.ColumnIndex + 65), pCell.RowIndex + 1);
                pEntidade.StatusImportacao = Constantes.StatusImportLote.ERRO;

                return;
            }
        }
        
        #region [ Validação dos dados ]

        private void InvokeValidarDadosDeImportacao()
        {
            base.BusyText = "Validando...";
            base.StartBusy();

            base.IsValidating = true;

            var contratos = GetDadosParaValidar(10);
           
            if (contratos.Count > 0)
            {
                _service.BeginValidarDadosDeImportacao(contratos,
                    (pAsyncResult) =>
                    {
                        Deployment.Current.Dispatcher.BeginInvoke(() =>
                        {
                            try
                            {
                                InvokeValidarDadosDeImportacao();

                                var retorno = ((ServiceOperacao.IServiceOperacao)pAsyncResult.AsyncState).EndValidarDadosDeImportacao(pAsyncResult);

                                if (retorno != null && retorno.Count > 0)
                                {
                                    foreach (var ret in retorno)
                                        this.ValidarRetornoDados(ret);
                                }

                            }
                            catch (Exception)
                            {
                                _erroNaValidacao = true;
                            }
                            finally
                            {
                                base.NotifyProperties();
                                base.EndBusy("Carregando...");

                                if (!base.IsBusy)
                                {
                                    //Se não estiver mais processando e ocorreu erro na validação 
                                    //deve retirar o status de processando
                                    if (_erroNaValidacao)
                                    {
                                        _erroNaValidacao = false;
                                        DadosPlanilha.Where(w => w.StatusImportacao == Constantes.StatusImportLote.PROCESSANDO).ToList().ForEach(r => r.StatusImportacao = "");
                                    }
                                }
                            }

                        });
                    }, _service);
            }
            else
            {
                base.IsValidating = false;

                base.NotifyProperties();
                base.EndBusy("Carregando...");
            }

        }

        private List<ServiceOperacao.ValidarImportacaoOperacao> GetDadosParaValidar(int pQtdItens)
        {
            var retorno = new List<ServiceOperacao.ValidarImportacaoOperacao>();
            int dup = 0;

            foreach (var item in DadosPlanilha)
            {
                if (string.IsNullOrEmpty(item.StatusImportacao))
                {
                    if (string.IsNullOrEmpty(item.CodigoContrato)
                        || string.IsNullOrEmpty(item.CodigoProduto) 
                        || string.IsNullOrEmpty(item.CodigoModalidade)
                        || item.IdCliente <= 0)
                    {
                        item.DescricaoErro = "Campos chave são de preenchimento obrigatório";
                        item.StatusImportacao = Constantes.StatusImportLote.ERRO;
                    }
                    else if (item.DataAbertura <= new DateTime(1900, 1, 1))
                    {
                        item.DescricaoErro = "Data de Abertura inválida";
                        item.StatusImportacao = Constantes.StatusImportLote.ERRO;
                    }
                    else if (item.DataVencimento <= new DateTime(1900, 1, 1))
                    {
                        item.DescricaoErro = "Data de Vencimento inválida";
                        item.StatusImportacao = Constantes.StatusImportLote.ERRO;
                    }
                    //else if (string.IsNullOrWhiteSpace(item.CodigoMoeda))
                    //{
                    //    item.DescricaoErro = "Campo Moeda é de preenchimento obrigatório";
                    //    item.StatusImportacao = Constantes.StatusImportLote.ERRO;
                    //}
                    else //if (string.IsNullOrEmpty(item.StatusImportacao))
                    {
                        //Verifico se item já foi adicionado para validação
                        dup = retorno.Count(a => a.CodigoContrato.Trim() == item.CodigoContrato.Trim()
                                                 && a.CodigoProduto.Trim() == item.CodigoProduto.Trim()
                                                 && a.CodigoModalidade.Trim() == item.CodigoModalidade.Trim()
                                                 && a.IdCliente == item.IdCliente);

                        if (dup > 0)
                        {
                            item.DescricaoErro = "Registro duplicado na planilha";
                            item.StatusImportacao = Constantes.StatusImportLote.ERRO;
                        }
                        else
                        {
                            item.StatusImportacao = Constantes.StatusImportLote.PROCESSANDO; //Sera validado

                            if (item.CodigoContrato != null && item.CodigoContrato.Length > 20)
                                item.CodigoContrato = item.CodigoContrato.Substring(0, 20);

                            if (item.CodigoProduto != null && item.CodigoProduto.Length > 15)
                                item.CodigoProduto = item.CodigoProduto.Substring(0, 15);

                            if (item.CodigoModalidade != null && item.CodigoModalidade.Length > 15)
                                item.CodigoModalidade = item.CodigoModalidade.Substring(0, 15);

                            if (item.CodigoMoeda != null && item.CodigoMoeda.Length > 3)
                                item.CodigoMoeda = item.CodigoMoeda.Substring(0, 3);

                            retorno.Add(GeneralHelper.SincProperties(item, new ServiceOperacao.ValidarImportacaoOperacao()));

                            if ((pQtdItens > 0) && (retorno.Count >= pQtdItens))
                                break;

                        }
                    }
                }
            }
            return retorno;
        }

        #endregion //Validacao dos dados

        #region [ Importação dos dados ]

        private void SalvarDadosDeImportacao()
        {
            int count = DadosPlanilha.Count(x => x.StatusImportacao != Constantes.StatusImportLote.FINALIZADO);
            if (count > 0)
            {
                if (_msgLogAuditoria == null)
                {
                    _msgLogAuditoria = new LogAuditoria();
                    _msgLogAuditoria.Mensagem = string.Format("Importação de Operação Manual! Quantidade: {0}", count);
                }

                _msgLogAuditoria.Acao = "NORISKBO: Importação em Lote";

                WRApplicationServiceHelper.SalvarLogAuditoria(_msgLogAuditoria);

                _msgLogAuditoria = null;
            }

            InvokeSalvarDadosDeImportacao();
        }

        private void InvokeSalvarDadosDeImportacao()
        {
            base.BusyText = "Importando Dados...";
            base.StartBusy();

            base.IsImporting = true;

            var contratos = GetDadosParaSalvar(10);

            if (contratos.Count > 0)
            {              
                _service.BeginSalvarDadosDeImportacao(contratos, AppHelper.NomeUsuario,
                   (pAsyncResult) =>
                   {
                       Deployment.Current.Dispatcher.BeginInvoke(delegate()
                       {
                           try
                           {
                               var retorno = ((ServiceOperacao.IServiceOperacao)pAsyncResult.AsyncState).EndSalvarDadosDeImportacao(pAsyncResult);

                               if (retorno != null && retorno.Count > 0)
                               {
                                   foreach (var item in retorno)
                                   {
                                       if (item.IdOperacao > 0)
                                           item.CodigoStatus = Constantes.StatusFluxoLM.RASCUNHO;
                                       else
                                           _erroNaImportacao = true;

                                       this.ValidarRetornoDados(item);
                                   }
                               }
                               
                               InvokeSalvarDadosDeImportacao();

                           }
                           catch (Exception ex)
                           {
                               _erroNaImportacao = true;
                               MessageBoxHelper.ShowErroMethod(base.TitleView, "ComandoImportarDados", ex);

                               base.StopBusy();
                           }
                           finally
                           {
                               base.NotifyProperties();
                               base.EndBusy("Carregando...");
                               
                               if (!IsBusy)
                               {
                                   if (!_erroNaImportacao)
                                   {
                                       MessageBoxHelper.ShowSucess("Importação em Lote", "Processo de Importação realizado com sucesso!");
                                   }
                                   else
                                   {
                                       MessageBoxHelper.ShowWarning("Importação em Lote", "Verifique os erros e tente novamente.");
                                       _erroNaImportacao = false;
                                   }
                               }

                           }
                       });

                   }, _service);
            }
            else
            {
                base.IsImporting = false;

                base.NotifyProperties();
                base.EndBusy("Carregando...");
            }
        }
        
        private List<ServiceOperacao.OperacaoManualImportacao> GetDadosParaSalvar(int pQtdItens)
        {
            var result = new List<ServiceOperacao.OperacaoManualImportacao>();

            var dados = DadosPlanilha.Where(a => a.StatusImportacao != Constantes.StatusImportLote.PROCESSANDO 
                                              && a.StatusImportacao != Constantes.StatusImportLote.FINALIZADO
                                              && a.StatusImportacao != Constantes.StatusImportLote.ERRO).Take(pQtdItens);

            foreach (var item in dados)
            {
                item.StatusImportacao = Constantes.StatusImportLote.PROCESSANDO;
                result.Add(GeneralHelper.SincProperties(item, new ServiceOperacao.OperacaoManualImportacao()));
            }

            return result;
        }

        #endregion //importacao

        #endregion //métodos adicionais
    }
}
